Namespace("org.wattdepot.gdata.makahiki");

// Creates a Standings Visualization with a standard appearance.
org.wattdepot.gdata.makahiki.Standings = function(configuration) {
  var configuration = configuration;
  var width = configuration.standingsWidth;
  var barWidth = 15;
  var barSpacing = 5;
  var myColor = configuration.greenIndicatorColor.replace('#','');
  var otherColor = configuration.grayIndicatorColor.replace('#','');
  var textColor = configuration.widgetTextColor.replace('#','');
  var backgroundColor = configuration.widgetBackgroundColor.replace('#','');

  // Draws the three components (title, chart, caption) of the standings visualization. 
  function draw(id, standings) {
    // Get the top-level div where this visualization should go. 
    element = document.getElementById(id);
    addTopLevelStyle(element);
    addTitleDiv(element, id, standings);
    // Determine if we are accessing points or energy data, and define the appropriate accessor.
    var units = (standings.info[0].points) ? "points" : "kWh";
    addChartDiv(element, id, standings, units);
    addCaptionDiv(element, id, standings, units);
  }

  // Adds 'global' CSS styling to the top-level div passed into this instance.
  function addTopLevelStyle(element) {
    element.style.backgroundColor = backgroundColor;
    element.style.margin = '0 auto';
    element.style.width = width + 'px';
  }

  function addTitleDiv(element, id, standings) {
    var divId = id + '__Title';
    var div = getElementByIdOrCreate(divId, 'div');
    element.appendChild(div);
    div.style.width = width + 'px';
    div.style.fontSize = '1.0em';
    div.style.fontWeight = 'bold';
    div.style.color = configuration.widgetHeaderColor;
    div.innerHTML = standings.title;
  }

  function addChartDiv(element, id, standings, units) {
    var divId = id + '__Chart';
    var div = getElementByIdOrCreate(divId, 'div');
    element.appendChild(div);
    var numStandings = standings.info.length;

    // create the datatable to hold the standings. 
    var datatable = new google.visualization.DataTable();
    datatable.addColumn('number');
    datatable.addRows(numStandings);
    for (var i = 0; i < numStandings; i++) {
      datatable.setCell(i, 0, standings.info[i][units]); 
    }

    // Now set up the chart options. 
    var options = {};
    // Chart type is a horizontal bar chart.
    options.cht = 'bhs';
    // We scale the X axis to be the max value + 20% to provide space for rankings markers.
    var maxValue = getMaxUnits(standings, units);
    var maxValuePad = Math.floor(maxValue * 0.20);
    options.chds = '0,' + (maxValue + maxValuePad);
    // Set the width and height.
    var height = ((barWidth + barSpacing) * (numStandings + 1));
    options.chs = width + 'x' + height;
    // Generate the bar colors
    var colors = [];
    if (!standings.myindex) {
      // if standings.myindex is not defined, then use myColor for all bars in graph.
      otherColor = myColor
    }
    for (var i = 0; i < numStandings; i++) {
      colors.push((i === standings.myindex) ? myColor : otherColor);
    }
    options.chco = colors.join('|');
    options.chbh = [barWidth, barSpacing, 0].join(',');
    options.chxt = 'x';
    options.chxr = '0,0,' + (maxValue + maxValuePad);
    options.chf = 'bg,s,' + backgroundColor;

    // Create the ranking markers.
    var rankingMarkers = [];
    for (var i = 0; i < numStandings; i++) {
      var label = (standings.info[i].label) ? ' ' + standings.info[i].label + ' ' : '';
      rankingMarkers.push('t#' + standings.info[i].rank + label + ((i === standings.myindex) ? ' (You)' : '') + ',' + textColor + ',0,' + i + ',12');
    }
    options.chm = rankingMarkers.join('|');
    // Create and draw the visualization.
    new google.visualization.ImageChart(div).draw(datatable, options); 
  }

  function addCaptionDiv(element, id, standings, units) {
    var divId = id + '__Caption';
    var div = getElementByIdOrCreate(divId, 'div');
    element.appendChild(div);
    div.style.width = width + 'px';
    div.style.fontSize = '0.7em';
    // only generate a caption if standings.myindex is defined.
    if (standings.myindex) {
      var myUnits = standings.info[standings.myindex][units];
      var myRanking = standings.info[standings.myindex].rank;
      var totalRankings = getMaxRank(standings);
      var overTakeInfo = '';
      if (standings.myindex > 0) {
	// I am not ranked number 1.
	var neighborIndex = standings.myindex - 1;
	var neighborRanking = standings.info[neighborIndex].rank;
	var neighborUnits = standings.info[neighborIndex][units];
	// points are ranked in descending order, kWh in ascending.
	var overTakeUnits = ((neighborUnits - myUnits) > 0) ? (neighborUnits - myUnits) : (myUnits - neighborUnits);
	var overTakeInfo = 
	  '  <br>' + 
	  ((standings.type === 'individual') ? 'I am currently ' : 'We are currently ')  + 
	  overTakeUnits + ' ' + units + ' behind #' + 
	  neighborRanking + '.';
      }
      var caption = 
	((standings.type === 'individual') ? 'I have ' : 'We have ')  + 
	myUnits + ' ' + units + ' and ' + 
	((standings.type === 'individual') ? ' am ' : ' are ')  + 
	'ranked #' + myRanking + ' out of ' + totalRankings + ' total.';
      div.innerHTML = caption + overTakeInfo;
    }
  }
    
  // Returns the pre-existing element with id 'id', or else creates and returns a new element with type elementType and that id.
  function getElementByIdOrCreate(id, elementType) {
    var element = document.getElementById(id);
    if (element) {
      return element;
    }
    else {
      element = document.createElement(elementType);
      element.setAttribute("id", id);
      return element;

    }
  }

  // Return the maximum value found in the standings.
  function getMaxUnits(standings, units) {
    var max = standings.info[0][units];
    var length = standings.info.length;
    for (var i = 1; i < length; i++) {
      if (standings.info[i][units] > max) {
	max = standings.info[i][units];
      }
    }
    return max;
  }

  // Return the maximum rank found in the standings.
  function getMaxRank(standings) {
    var max = standings.info[0].rank;
    var length = standings.info.length;
    for (var i = 1; i < length; i++) {
      if (standings.info[i].rank > max) {
	max = standings.info[i].rank;
      }
    }
    return max;
  }
  
  function setWidth(newWidth) {
    width=newWidth;
  }


  return {
    // Public interface to this function. 
    draw : draw,
    setWidth : setWidth
  };
}


